/*
MIT License

Copyright (c) 2022 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo
*/

#include "simodo/interpret/SemanticOperationsEnumsLoader.h" 

#include "simodo/variable/json/LexicalParametersLoader.h"
#include "simodo/inout/token/Tokenizer.h"
#include "simodo/inout/token/FileStream.h"
#include "simodo/inout/convert/functions.h"

#if __cplusplus >= __cpp_2017
#include <filesystem>
namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::filesystem::experimental;
#endif


namespace simodo::interpret
{
    variable::VariableSet_t readSemanticModuleOperations(const std::string & file_path, inout::LexicalParameters & lex)
    {
        variable::VariableSet_t res;

        inout::FileStream in(file_path);

        if (!in.good())
            return res;

        inout::Tokenizer tokenizer(0, in, lex);
        inout::Token     t = tokenizer.getToken();

        while(t.type() != inout::LexemeType::Empty) {
            if (t.type() != inout::LexemeType::Id)
                break;

            std::u16string id = t.lexeme();

            t = tokenizer.getToken();

            if (t.type() != inout::LexemeType::Punctuation || t.lexeme() != u"=")
                break;

            t = tokenizer.getToken();

            if (t.type() != inout::LexemeType::Number
             || t.qualification() != inout::TokenQualification::Integer)
                break;

            int64_t number = std::stol(inout::toU8(t.lexeme()));

            t = tokenizer.getToken();

            if (t.type() != inout::LexemeType::Punctuation || t.lexeme() != u",")
                break;

            res.push_back({id, number});

            t = tokenizer.getToken();
        }

        return res;
    }

    variable::VariableSet_t loadSemanticOperationsEnums(const std::string & grammar_dir)
    {
        variable::VariableSet_t res;
        const fs::path path_to_grammar {grammar_dir};

        if (!fs::exists(path_to_grammar))
            return res;

        inout::LexicalParameters lex;

        bool ok = variable::loadLexicalParameters((path_to_grammar/"lex"/"cpp.json").string(), lex);

        if (!ok)
            return res;

        const fs::path path_to_ops { path_to_grammar / "ops"};

        for (auto const & f : fs::directory_iterator{path_to_ops}) {
            std::u16string extension = f.path().extension().u16string();
            std::u16string host_name = extension.empty() ? u"" : extension.substr(1);
            variable::VariableSet_t ops = readSemanticModuleOperations(f.path().string(), lex);
            variable::VariableSet_t host {{
                {u"host", host_name},
                {u"op", variable::Object {ops}},
            }};

            res.push_back({f.path().stem().u16string(), variable::Object {host}});
        }

        return res;
    }

}